home *** CD-ROM | disk | FTP | other *** search
/ Super PC 34 / Super PC 34 (Shareware).iso / spc / UTIL / DJGPP2 / V2 / DJLSR200.ZIP / src / libc / ansi / stdio / doprnt.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-01-24  |  20.1 KB  |  843 lines

  1. /* Copyright (C) 1996 DJ Delorie, see COPYING.DJ for details */
  2. /* Copyright (C) 1994 DJ Delorie, see COPYING.DJ for details */
  3. #include <libc/stubs.h>
  4. #include <sys/types.h>
  5. #include <stdarg.h>
  6. #include <stdio.h>
  7. #include <ctype.h>
  8. #include <locale.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11. #include <math.h>
  12. #include <libc/file.h>
  13. #include <libc/stdiohk.h>
  14. #include <libc/local.h>
  15.  
  16. static char decimal = '.';
  17.  
  18. /* 11-bit exponent (VAX G floating point) is 308 decimal digits */
  19. #define    MAXEXP        308
  20. #define MAXEXPLD        4952 /* this includes subnormal numbers */
  21. /* 128 bit fraction takes up 39 decimal digits; max reasonable precision */
  22. #define    MAXFRACT    39
  23.  
  24. #define    DEFPREC        6
  25. #define    DEFLPREC    6
  26.  
  27. #define    BUF        (MAXEXPLD+MAXFRACT+1)    /* + decimal point */
  28.  
  29. #define    PUTC(ch)    (void) putc(ch, fp)
  30.  
  31. #define ARG(basetype) \
  32.     _ulong = flags&LONGINT ? va_arg(argp, long basetype) : \
  33.         flags&SHORTINT ? (short basetype)va_arg(argp, int) : \
  34.         va_arg(argp, int)
  35.  
  36. static int nan = 0;
  37.  
  38. static __inline__ int todigit(char c)
  39. {
  40.   if (c<='0') return 0;
  41.   if (c>='9') return 9;
  42.   return c-'0';
  43. }
  44. static __inline__ char tochar(int n)
  45. {
  46.   if (n>=9) return '9';
  47.   if (n<=0) return '0';
  48.   return n+'0';
  49. }
  50.  
  51. /* have to deal with the negative buffer count kludge */
  52.  
  53. #define    LONGINT        0x01        /* long integer */
  54. #define    LONGDBL        0x02        /* long double */
  55. #define    SHORTINT    0x04        /* short integer */
  56. #define    ALT        0x08        /* alternate form */
  57. #define    LADJUST        0x10        /* left adjustment */
  58. #define    ZEROPAD        0x20        /* zero (as opposed to blank) pad */
  59. #define    HEXPREFIX    0x40        /* add 0x or 0X prefix */
  60.  
  61. static cvtl(long double number, int prec, int flags, char *signp,
  62.         unsigned char fmtch, char *startp, char *endp);
  63. static char *roundl(long double fract, int *expv, char *start, char *end,
  64.             char ch, char *signp);
  65. static char *exponentl(char *p, int expv, unsigned char fmtch);
  66. #ifdef __GO32__
  67. static int isspeciall(long double d, char *bufp);
  68. #endif
  69.  
  70. static char NULL_REP[] = "(null)";
  71.  
  72. int
  73. _doprnt(const char *fmt0, va_list argp, FILE *fp)
  74. {
  75.   const char *fmt;        /* format string */
  76.   int ch;            /* character from fmt */
  77.   int cnt;            /* return value accumulator */
  78.   int n;            /* random handy integer */
  79.   char *t;            /* buffer pointer */
  80.   long double _ldouble;        /* double and long double precision arguments
  81.                    %L.[eEfgG] */
  82.   unsigned long _ulong;        /* integer arguments %[diouxX] */
  83.   int base;            /* base for [diouxX] conversion */
  84.   int dprec;            /* decimal precision in [diouxX] */
  85.   int fieldsz;            /* field size expanded by sign, etc */
  86.   int flags;            /* flags as above */
  87.   int fpprec;            /* `extra' floating precision in [eEfgG] */
  88.   int prec;            /* precision from format (%.3d), or -1 */
  89.   int realsz;            /* field size expanded by decimal precision */
  90.   int size;            /* size of converted field or string */
  91.   int width;            /* width from format (%8d), or 0 */
  92.   char sign;            /* sign prefix (' ', '+', '-', or \0) */
  93.   char softsign;        /* temporary negative sign for floats */
  94.   const char *digs;        /* digits for [diouxX] conversion */
  95.   char buf[BUF];        /* space for %c, %[diouxX], %[eEfgG] */
  96.  
  97.   decimal = localeconv()->decimal_point[0];
  98.  
  99.   if (fp->_flag & _IORW)
  100.   {
  101.     fp->_flag |= _IOWRT;
  102.     fp->_flag &= ~(_IOEOF|_IOREAD);
  103.   }
  104.   if ((fp->_flag & _IOWRT) == 0)
  105.     return (EOF);
  106.  
  107.   fmt = fmt0;
  108.   digs = "0123456789abcdef";
  109.   for (cnt = 0;; ++fmt)
  110.   {
  111.     n = fp->_cnt;
  112.     for (t = (char *)fp->_ptr; (ch = *fmt) && ch != '%';
  113.      ++cnt, ++fmt)
  114.       if ((--n < 0
  115.        && (!(fp->_flag & _IOLBF) || -n >= fp->_bufsiz))
  116.       || (ch == '\n' && fp->_flag & _IOLBF))
  117.       {
  118.     fp->_cnt = n;
  119.     fp->_ptr = t;
  120.     (void) _flsbuf((unsigned char)ch, fp);
  121.     n = fp->_cnt;
  122.     t = (char *)fp->_ptr;
  123.       }
  124.       else
  125.     *t++ = ch;
  126.     fp->_cnt = n;
  127.     fp->_ptr = t;
  128.     if (!ch)
  129.       return cnt;
  130.     flags = 0; dprec = 0; fpprec = 0; width = 0;
  131.     prec = -1;
  132.     sign = '\0';
  133.   rflag:
  134.     switch (*++fmt)
  135.     {
  136.     case ' ':
  137.       /*
  138.        * ``If the space and + flags both appear, the space
  139.        * flag will be ignored.''
  140.        *    -- ANSI X3J11
  141.        */
  142.       if (!sign)
  143.     sign = ' ';
  144.       goto rflag;
  145.     case '#':
  146.       flags |= ALT;
  147.       goto rflag;
  148.     case '*':
  149.       /*
  150.        * ``A negative field width argument is taken as a
  151.        * - flag followed by a  positive field width.''
  152.        *    -- ANSI X3J11
  153.        * They don't exclude field widths read from args.
  154.        */
  155.       if ((width = va_arg(argp, int)) >= 0)
  156.     goto rflag;
  157.       width = -width;
  158.       /* FALLTHROUGH */
  159.     case '-':
  160.       flags |= LADJUST;
  161.       goto rflag;
  162.     case '+':
  163.       sign = '+';
  164.       goto rflag;
  165.     case '.':
  166.       if (*++fmt == '*')
  167.     n = va_arg(argp, int);
  168.       else
  169.       {
  170.     n = 0;
  171.     while (isascii(*fmt) && isdigit(*fmt))
  172.       n = 10 * n + todigit(*fmt++);
  173.     --fmt;
  174.       }
  175.       prec = n < 0 ? -1 : n;
  176.       goto rflag;
  177.     case '0':
  178.       /*
  179.        * ``Note that 0 is taken as a flag, not as the
  180.        * beginning of a field width.''
  181.        *    -- ANSI X3J11
  182.        */
  183.       flags |= ZEROPAD;
  184.       goto rflag;
  185.     case '1': case '2': case '3': case '4':
  186.     case '5': case '6': case '7': case '8': case '9':
  187.       n = 0;
  188.       do {
  189.     n = 10 * n + todigit(*fmt);
  190.       } while (isascii(*++fmt) && isdigit(*fmt));
  191.       width = n;
  192.       --fmt;
  193.       goto rflag;
  194.     case 'L':
  195.       flags |= LONGDBL;
  196.       goto rflag;
  197.     case 'h':
  198.       flags |= SHORTINT;
  199.       goto rflag;
  200.     case 'l':
  201.       flags |= LONGINT;
  202.       goto rflag;
  203.     case 'c':
  204.       *(t = buf) = va_arg(argp, int);
  205.       size = 1;
  206.       sign = '\0';
  207.       goto pforw;
  208.     case 'D':
  209.       flags |= LONGINT;
  210.       /*FALLTHROUGH*/
  211.     case 'd':
  212.     case 'i':
  213.       ARG(int);
  214.       if ((long)_ulong < 0)
  215.       {
  216.     _ulong = -_ulong;
  217.     sign = '-';
  218.       }
  219.       base = 10;
  220.       goto number;
  221.     case 'e':
  222.     case 'E':
  223.     case 'f':
  224.     case 'g':
  225.     case 'G':
  226.       if (flags & LONGDBL)
  227.     _ldouble = va_arg(argp, long double);
  228.       else
  229.     _ldouble = (long double)va_arg(argp, double);
  230.       /*
  231.        * don't do unrealistic precision; just pad it with
  232.        * zeroes later, so buffer size stays rational.
  233.        */
  234.       if (prec > MAXFRACT)
  235.       {
  236.     if (*fmt != 'g' && (*fmt != 'G' || (flags&ALT)))
  237.       fpprec = prec - MAXFRACT;
  238.     prec = MAXFRACT;
  239.       }
  240.       else if (prec == -1)
  241.       {
  242.     if (flags&LONGINT)
  243.       prec = DEFLPREC;
  244.     else
  245.       prec = DEFPREC;
  246.       }
  247.       /*
  248.        * softsign avoids negative 0 if _double is < 0 and
  249.        * no significant digits will be shown
  250.        */
  251.       if (_ldouble < 0)
  252.       {
  253.     softsign = '-';
  254.     _ldouble = -_ldouble;
  255.       }
  256.       else
  257.     softsign = 0;
  258.       /*
  259.        * cvt may have to round up past the "start" of the
  260.        * buffer, i.e. ``intf("%.2f", (double)9.999);'';
  261.        * if the first char isn't NULL, it did.
  262.        */
  263.       *buf = NULL;
  264.       size = cvtl(_ldouble, prec, flags, &softsign, *fmt, buf,
  265.           buf + sizeof(buf));
  266.       if (softsign && !nan)
  267.     sign = '-';
  268.       nan = 0;
  269.       t = *buf ? buf : buf + 1;
  270.       goto pforw;
  271.     case 'n':
  272.       if (flags & LONGINT)
  273.     *va_arg(argp, long *) = cnt;
  274.       else if (flags & SHORTINT)
  275.     *va_arg(argp, short *) = cnt;
  276.       else
  277.     *va_arg(argp, int *) = cnt;
  278.       break;
  279.     case 'O':
  280.       flags |= LONGINT;
  281.       /*FALLTHROUGH*/
  282.     case 'o':
  283.       ARG(unsigned);
  284.       base = 8;
  285.       goto nosign;
  286.     case 'p':
  287.       /*
  288.        * ``The argument shall be a pointer to void.  The
  289.        * value of the pointer is converted to a sequence
  290.        * of printable characters, in an implementation-
  291.        * defined manner.''
  292.        *    -- ANSI X3J11
  293.        */
  294.       /* NOSTRICT */
  295.       _ulong = (unsigned long)va_arg(argp, void *);
  296.       base = 16;
  297.       goto nosign;
  298.     case 's':
  299.       if (!(t = va_arg(argp, char *)))
  300.     t = NULL_REP;
  301.       if (prec >= 0)
  302.       {
  303.     /*
  304.      * can't use strlen; can only look for the
  305.      * NUL in the first `prec' characters, and
  306.      * strlen() will go further.
  307.      */
  308.     char *p            /*, *memchr() */;
  309.  
  310.     if ((p = memchr(t, 0, prec)))
  311.     {
  312.       size = p - t;
  313.       if (size > prec)
  314.         size = prec;
  315.     }
  316.     else
  317.       size = prec;
  318.       }
  319.       else
  320.     size = strlen(t);
  321.       sign = '\0';
  322.       goto pforw;
  323.     case 'U':
  324.       flags |= LONGINT;
  325.       /*FALLTHROUGH*/
  326.     case 'u':
  327.       ARG(unsigned);
  328.       base = 10;
  329.       goto nosign;
  330.     case 'X':
  331.       digs = "0123456789ABCDEF";
  332.       /* FALLTHROUGH */
  333.     case 'x':
  334.       ARG(unsigned);
  335.       base = 16;
  336.       /* leading 0x/X only if non-zero */
  337.       if (flags & ALT && _ulong != 0)
  338.     flags |= HEXPREFIX;
  339.  
  340.       /* unsigned conversions */
  341.     nosign:            sign = '\0';
  342.       /*
  343.        * ``... diouXx conversions ... if a precision is
  344.        * specified, the 0 flag will be ignored.''
  345.        *    -- ANSI X3J11
  346.        */
  347.     number:            if ((dprec = prec) >= 0)
  348.       flags &= ~ZEROPAD;
  349.  
  350.       /*
  351.        * ``The result of converting a zero value with an
  352.        * explicit precision of zero is no characters.''
  353.        *    -- ANSI X3J11
  354.        */
  355.       t = buf + BUF;
  356.       if (_ulong != 0 || prec != 0)
  357.       {
  358.     do {
  359.       *--t = digs[_ulong % base];
  360.       _ulong /= base;
  361.     } while (_ulong);
  362.     digs = "0123456789abcdef";
  363.     if (flags & ALT && base == 8 && *t != '0')
  364.       *--t = '0';        /* octal leading 0 */
  365.       }
  366.       size = buf + BUF - t;
  367.  
  368.     pforw:
  369.       /*
  370.        * All reasonable formats wind up here.  At this point,
  371.        * `t' points to a string which (if not flags&LADJUST)
  372.        * should be padded out to `width' places.  If
  373.        * flags&ZEROPAD, it should first be prefixed by any
  374.        * sign or other prefix; otherwise, it should be blank
  375.        * padded before the prefix is emitted.  After any
  376.        * left-hand padding and prefixing, emit zeroes
  377.        * required by a decimal [diouxX] precision, then print
  378.        * the string proper, then emit zeroes required by any
  379.        * leftover floating precision; finally, if LADJUST,
  380.        * pad with blanks.
  381.        */
  382.  
  383.       /*
  384.        * compute actual size, so we know how much to pad
  385.        * fieldsz excludes decimal prec; realsz includes it
  386.        */
  387.       fieldsz = size + fpprec;
  388.       realsz = dprec > fieldsz ? dprec : fieldsz;
  389.       if (sign)
  390.     realsz++;
  391.       if (flags & HEXPREFIX)
  392.     realsz += 2;
  393.  
  394.       /* right-adjusting blank padding */
  395.       if ((flags & (LADJUST|ZEROPAD)) == 0 && width)
  396.     for (n = realsz; n < width; n++)
  397.       PUTC(' ');
  398.       /* prefix */
  399.       if (sign)
  400.     PUTC(sign);
  401.       if (flags & HEXPREFIX)
  402.       {
  403.     PUTC('0');
  404.     PUTC((char)*fmt);
  405.       }
  406.       /* right-adjusting zero padding */
  407.       if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
  408.     for (n = realsz; n < width; n++)
  409.       PUTC('0');
  410.       /* leading zeroes from decimal precision */
  411.       for (n = fieldsz; n < dprec; n++)
  412.     PUTC('0');
  413.  
  414.       /* the string or number proper */
  415.       n = size;
  416.       if (fp->_cnt - n >= 0 && (fp->_flag & _IOLBF) == 0)
  417.       {
  418.     fp->_cnt -= n;
  419.     memcpy((char *)fp->_ptr, t, n);
  420.     fp->_ptr += n;
  421.       }
  422.       else
  423.     while (--n >= 0)
  424.       PUTC(*t++);
  425.       /* trailing f.p. zeroes */
  426.       while (--fpprec >= 0)
  427.     PUTC('0');
  428.       /* left-adjusting padding (always blank) */
  429.       if (flags & LADJUST)
  430.     for (n = realsz; n < width; n++)
  431.       PUTC(' ');
  432.       /* finally, adjust cnt */
  433.       cnt += width > realsz ? width : realsz;
  434.       break;
  435.     case '\0':            /* "%?" prints ?, unless ? is NULL */
  436.       return cnt;
  437.     default:
  438.       PUTC((char)*fmt);
  439.       cnt++;
  440.     }
  441.   }
  442.   /* NOTREACHED */
  443. }
  444.  
  445. static long double pten[] =
  446. {
  447.   1e1L, 1e2L, 1e4L, 1e8L, 1e16L, 1e32L, 1e64L, 1e128L, 1e256L,
  448.   1e512L, 1e1024L, 1e2048L, 1e4096L
  449. };
  450.  
  451. static long double ptenneg[] =
  452. {
  453.   1e-1L, 1e-2L, 1e-4L, 1e-8L, 1e-16L, 1e-32L, 1e-64L, 1e-128L, 1e-256L,
  454.   1e-512L, 1e-1024L, 1e-2048L, 1e-4096L
  455. };
  456.  
  457. #define MAXP 4096
  458. #define NP   12
  459. #define P    (4294967296.0L * 4294967296.0L * 2.0L)   /* 2^65 */
  460. static long double INVPREC = P;
  461. static long double PREC = 1.0L/P;
  462. #undef P
  463. /*
  464.  * Defining FAST_LDOUBLE_CONVERSION results in a little bit faster
  465.  * version, which might be less accurate (about 1 bit) for long
  466.  * double. For 'normal' double it doesn't matter.
  467.  */
  468. /* #define FAST_LDOUBLE_CONVERSION */
  469.  
  470. static int
  471. cvtl(long double number, int prec, int flags, char *signp, unsigned char fmtch,
  472.      char *startp, char *endp)
  473. {
  474.   char *p, *t;
  475.   long double fract;
  476.   int dotrim, expcnt, gformat;
  477.   long double integer, tmp;
  478.  
  479.   if ((expcnt = isspeciall(number, startp)))
  480.     return(expcnt);
  481.  
  482.   dotrim = expcnt = gformat = 0;
  483.   /* fract = modfl(number, &integer); */
  484.   integer = number;
  485.  
  486.   /* get an extra slot for rounding. */
  487.   t = ++startp;
  488.  
  489.   p = endp - 1;
  490.   if (integer)
  491.   {
  492.     int i, lp=NP, pt=MAXP;
  493. #ifndef FAST_LDOUBLE_CONVERSION
  494.     long double oint = integer, dd=1.0L;
  495. #endif
  496.     if (integer > INVPREC)
  497.     {
  498.       integer *= PREC;
  499.       while(lp >= 0) {
  500.     if (integer >= pten[lp])
  501.     {
  502.       expcnt += pt;
  503.       integer *= ptenneg[lp];
  504. #ifndef FAST_LDOUBLE_CONVERSION
  505.       dd *= pten[lp];
  506. #endif
  507.     }
  508.     pt >>= 1;
  509.     lp--;
  510.       }
  511. #ifndef FAST_LDOUBLE_CONVERSION
  512.       integer = oint/dd;
  513. #else
  514.       integer *= INVPREC;
  515. #endif
  516.     }
  517.     /*
  518.      * Do we really need this ?
  519.      */
  520.     for (i = 0; i < expcnt; i++)
  521.       *p-- = '0';
  522.   }
  523.   number = integer;
  524.   fract = modfl(number, &integer);
  525.   /*
  526.    * get integer portion of number; put into the end of the buffer; the
  527.    * .01 is added for modf(356.0 / 10, &integer) returning .59999999...
  528.    */
  529.   for (; integer; ++expcnt)
  530.   {
  531.     tmp = modfl(integer * 0.1L , &integer);
  532.     *p-- = tochar((int)((tmp + .01L) * 10));
  533.   }
  534.   switch(fmtch)
  535.   {
  536.   case 'f':
  537.     /* reverse integer into beginning of buffer */
  538.     if (expcnt)
  539.       for (; ++p < endp; *t++ = *p);
  540.     else
  541.       *t++ = '0';
  542.     /*
  543.      * if precision required or alternate flag set, add in a
  544.      * decimal point.
  545.      */
  546.     if (prec || flags&ALT)
  547.       *t++ = decimal;
  548.     /* if requires more precision and some fraction left */
  549.     if (fract)
  550.     {
  551.       if (prec)
  552.     do {
  553.       fract = modfl(fract * 10.0L, &tmp);
  554.       *t++ = tochar((int)tmp);
  555.     } while (--prec && fract);
  556.       if (fract)
  557.     startp = roundl(fract, (int *)NULL, startp,
  558.             t - 1, (char)0, signp);
  559.     }
  560.     for (; prec--; *t++ = '0');
  561.     break;
  562.   case 'e':
  563.   case 'E':
  564.   eformat:
  565.     if (expcnt)
  566.     {
  567.       *t++ = *++p;
  568.       if (prec || flags&ALT)
  569.     *t++ = decimal;
  570.       /* if requires more precision and some integer left */
  571.       for (; prec && ++p < endp; --prec)
  572.     *t++ = *p;
  573.       /*
  574.        * if done precision and more of the integer component,
  575.        * round using it; adjust fract so we don't re-round
  576.        * later.
  577.        */
  578.       if (!prec && ++p < endp)
  579.       {
  580.     fract = 0;
  581.     startp = roundl((long double)0.0L, &expcnt,
  582.             startp, t - 1, *p, signp);
  583.       }
  584.       /* adjust expcnt for digit in front of decimal */
  585.       --expcnt;
  586.     }
  587.     /* until first fractional digit, decrement exponent */
  588.     else if (fract)
  589.     {
  590.       int lp=NP, pt=MAXP;
  591. #ifndef FAST_LDOUBLE_CONVERSION
  592.       long double ofract = fract, dd=1.0L;
  593. #endif
  594.       expcnt = -1;
  595.       if (fract < PREC)
  596.       {
  597.     fract *= INVPREC;
  598.     while(lp >= 0)
  599.     {
  600.       if (fract <= ptenneg[lp])
  601.       {
  602.         expcnt -= pt;
  603.         fract *= pten[lp];
  604. #ifndef FAST_LDOUBLE_CONVERSION
  605.         dd *= pten[lp];
  606. #endif
  607.       }
  608.       pt >>= 1;
  609.       lp--;
  610.     }
  611. #ifndef FAST_LDOUBLE_CONVERSION
  612.     fract = ofract*dd;
  613. #else
  614.     fract *= PREC;
  615. #endif
  616.       }
  617.       /* adjust expcnt for digit in front of decimal */
  618.       for (            /* expcnt = -1 */ ;; --expcnt)
  619.       {
  620.     fract = modfl(fract * 10.0L, &tmp);
  621.     if (tmp)
  622.       break;
  623.       }
  624.       *t++ = tochar((int)tmp);
  625.       if (prec || flags&ALT)
  626.     *t++ = decimal;
  627.     }
  628.     else
  629.     {
  630.       *t++ = '0';
  631.       if (prec || flags&ALT)
  632.     *t++ = decimal;
  633.     }
  634.     /* if requires more precision and some fraction left */
  635.     if (fract)
  636.     {
  637.       if (prec)
  638.     do {
  639.       fract = modfl(fract * 10.0L, &tmp);
  640.       *t++ = tochar((int)tmp);
  641.     } while (--prec && fract);
  642.       if (fract)
  643.     startp = roundl(fract, &expcnt, startp,
  644.             t - 1, (char)0, signp);
  645.     }
  646.     /* if requires more precision */
  647.     for (; prec--; *t++ = '0');
  648.  
  649.     /* unless alternate flag, trim any g/G format trailing 0's */
  650.     if (gformat && !(flags&ALT))
  651.     {
  652.       while (t > startp && *--t == '0');
  653.       if (*t == decimal)
  654.     --t;
  655.       ++t;
  656.     }
  657.     t = exponentl(t, expcnt, fmtch);
  658.     break;
  659.   case 'g':
  660.   case 'G':
  661.     /* a precision of 0 is treated as a precision of 1. */
  662.     if (!prec)
  663.       ++prec;
  664.     /*
  665.      * ``The style used depends on the value converted; style e
  666.      * will be used only if the exponent resulting from the
  667.      * conversion is less than -4 or greater than the precision.''
  668.      *    -- ANSI X3J11
  669.      */
  670.     if (expcnt > prec || (!expcnt && fract && fract < .0001))
  671.     {
  672.       /*
  673.        * g/G format counts "significant digits, not digits of
  674.        * precision; for the e/E format, this just causes an
  675.        * off-by-one problem, i.e. g/G considers the digit
  676.        * before the decimal point significant and e/E doesn't
  677.        * count it as precision.
  678.        */
  679.       --prec;
  680.       fmtch -= 2;        /* G->E, g->e */
  681.       gformat = 1;
  682.       goto eformat;
  683.     }
  684.     /*
  685.      * reverse integer into beginning of buffer,
  686.      * note, decrement precision
  687.      */
  688.     if (expcnt)
  689.       for (; ++p < endp; *t++ = *p, --prec);
  690.     else
  691.       *t++ = '0';
  692.     /*
  693.      * if precision required or alternate flag set, add in a
  694.      * decimal point.  If no digits yet, add in leading 0.
  695.      */
  696.     if (prec || flags&ALT)
  697.     {
  698.       dotrim = 1;
  699.       *t++ = decimal;
  700.     }
  701.     else
  702.       dotrim = 0;
  703.     /* if requires more precision and some fraction left */
  704.     while (prec && fract)
  705.     {
  706.       fract = modfl(fract * 10.0L, &tmp);
  707.       *t++ = tochar((int)tmp);
  708.       prec--;
  709.     }
  710.     if (fract)
  711.       startp = roundl(fract, (int *)NULL, startp, t - 1,
  712.               (char)0, signp);
  713.     /* alternate format, adds 0's for precision, else trim 0's */
  714.     if (flags&ALT)
  715.       for (; prec--; *t++ = '0');
  716.     else if (dotrim)
  717.     {
  718.       while (t > startp && *--t == '0');
  719.       if (*t != decimal)
  720.     ++t;
  721.     }
  722.   }
  723.   return t - startp;
  724. }
  725.  
  726. static char *
  727. roundl(long double fract, int *expv, char *start, char *end, char ch,
  728.        char *signp)
  729. {
  730.   long double tmp;
  731.  
  732.   if (fract)
  733.   {
  734.     if (fract == 0.5L)
  735.     {
  736.       char *e = end;
  737.       if (*e == '.')
  738.     e--;
  739.       if (*e == '0' || *e == '2' || *e == '4'
  740.       || *e == '6' || *e == '8')
  741.       {
  742.     tmp = 3.0;
  743.     goto start;
  744.       }
  745.     }
  746.     (void)modfl(fract * 10.0L, &tmp);
  747.   }
  748.   else
  749.     tmp = todigit(ch);
  750.  start:
  751.   if (tmp > 4)
  752.     for (;; --end)
  753.     {
  754.       if (*end == decimal)
  755.     --end;
  756.       if (++*end <= '9')
  757.     break;
  758.       *end = '0';
  759.       if (end == start)
  760.       {
  761.     if (expv)
  762.     {        /* e/E; increment exponent */
  763.       *end = '1';
  764.       ++*expv;
  765.     }
  766.     else
  767.     {            /* f; add extra digit */
  768.       *--end = '1';
  769.       --start;
  770.     }
  771.     break;
  772.       }
  773.     }
  774.   /* ``"%.3f", (double)-0.0004'' gives you a negative 0. */
  775.   else if (*signp == '-')
  776.     for (;; --end)
  777.     {
  778.       if (*end == decimal)
  779.     --end;
  780.       if (*end != '0')
  781.     break;
  782.       if (end == start)
  783.     *signp = 0;
  784.     }
  785.   return start;
  786. }
  787.  
  788. static char *
  789. exponentl(char *p, int expv, unsigned char fmtch)
  790. {
  791.   char *t;
  792.   char expbuf[MAXEXPLD];
  793.  
  794.   *p++ = fmtch;
  795.   if (expv < 0)
  796.   {
  797.     expv = -expv;
  798.     *p++ = '-';
  799.   }
  800.   else
  801.     *p++ = '+';
  802.   t = expbuf + MAXEXPLD;
  803.   if (expv > 9)
  804.   {
  805.     do {
  806.       *--t = tochar(expv % 10);
  807.     } while ((expv /= 10) > 9);
  808.     *--t = tochar(expv);
  809.     for (; t < expbuf + MAXEXPLD; *p++ = *t++);
  810.   }
  811.   else
  812.   {
  813.     *p++ = '0';
  814.     *p++ = tochar(expv);
  815.   }
  816.   return p;
  817. }
  818.  
  819. static int
  820. isspeciall(long double d, char *bufp)
  821. {
  822.   struct IEEExp {
  823.     unsigned manl:32;
  824.     unsigned manh:32;
  825.     unsigned exp:15;
  826.     unsigned sign:1;
  827.   } *ip = (struct IEEExp *)&d;
  828.  
  829.   nan = 0;  /* don't assume the static is 0 (emacs) */
  830.   if (ip->exp != 0x7fff)
  831.     return(0);
  832.   if ((ip->manh & 0x7fffffff) || ip->manl)
  833.   {
  834.     strcpy(bufp, "NaN");
  835.     nan = 1;            /* kludge: we don't need the sign,  it's not nice
  836.                    but it should work */
  837.   }
  838.   else
  839.     (void)strcpy(bufp, "Inf");
  840.   return(3);
  841. }
  842.  
  843.